package liquor.collection;

import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import liquor.exception.LiquorException;

/**
 * RoundRobin 클래스
 * 마지막 끝에 인덱스에 도달하였을대 처음을 next로 판단하는 자료구조
 *  
 * @author 박성준
 */
public class RoundRobin<E> implements Collection<E> {
	private List<E> data;	
	
	/**
	 * 기본생성자
	 */
	public RoundRobin() {
		data = new LinkedList<E>();
	}
	
	/**
	 * 문자열 나열로 {@link RoundRobin}을 만든다.
	 * @param args
	 */
	public RoundRobin(E ... args) {
		data = new LinkedList<E>(Arrays.asList(args));
	}
	
	/**
	 * {@link Collection}의 데이터로 생성한다.
	 */
	public RoundRobin(Collection<? extends E> c) {
		data = new LinkedList<E>(c);		
	}
	
	
	/**
	 * 항목을 추가한다. 단, null은 추가하지 않는다.
	 * @param item
	 * @return boolean
	 */
	public boolean add(E item) {
		if (item == null) {
			return false;
		}
		
		return data.add(item);
	}
		
	/**
	 * 항목을 삭제한다. 존재하지 않는 항목은 삭제되지 않는다.
	 * @param o
	 */
	public boolean remove(Object o) {
		return data.remove(o);
	}
	
	/**
	 * 입력으로 들어온 인자의 다음값을 반환한다.
	 * 이때, 입력으로 들어온 인자를 찾지 못하면 {@link LiquorException}을 던진다.
	 * 
	 * @param item
	 * @return Object
	 */
	public E next(E item) {
		int index = data.indexOf(item);
		if (index <0) {
			throw new LiquorException();
		}
		
		int nextIndex = index + 1;
		if (nextIndex >= data.size()) {
			nextIndex = 0;
		}
		
		return data.get(nextIndex);
	}
	
	/**
	 * 입력으로 들어온 인자의 이전값을 반환한다.
	 * 이때, 입력으로 들어온 인자를 찾지 못하면 {@link LiquorException}을 던진다.
	 * 
	 * @param item
	 * @return Object
	 */
	public E before(E item) {
		int index = data.indexOf(item);
		if (index <0) {
			throw new LiquorException();
		}
		
		int nextIndex = index -1;
		if (nextIndex < 0) {
			nextIndex = data.size()-1;
		}
		
		return data.get(nextIndex);
	}

	/**
	 * 내재된 데이터 갯수
	 */
	public int size() {
		return data.size();
	}

	/**
	 * 비어있는지 여부
	 */
	public boolean isEmpty() {
		return data.isEmpty();
	}

	/**
	 * 해당 객체를 가지고 있는지 여부
	 */
	public boolean contains(Object o) {		
		return data.contains(o);
	}

	/**
	 * 내재된 데이터의 Iterator
	 */
	public Iterator<E> iterator() {		
		return data.iterator();
	}

	public Object[] toArray() {		
		return data.toArray();
	}

	public <T> T[] toArray(T[] a) {		
		return data.toArray(a);
	}

	public boolean containsAll(Collection<?> c) {		
		return data.containsAll(c);
	}

	public boolean addAll(Collection<? extends E> c) {		
		return data.addAll(c);
	}

	public boolean removeAll(Collection<?> c) {		
		return data.removeAll(c);
	}

	public boolean retainAll(Collection<?> c) {		
		return data.retainAll(c);
	}

	public void clear() {
		data.clear();
	}
}
